package com.tjcm.tjcminspectmanager.manager;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.emagsoftware.net.http.HttpConnectionManager;
import cn.emagsoftware.net.http.HttpResponseResultStream;
import cn.emagsoftware.util.CodeException;
import cn.emagsoftware.xmlpull.simpledom.Element;
import cn.emagsoftware.xmlpull.simpledom.SimpleDomManager;

import com.tjcm.tjcminspectmanager.model.ContentItem;
import com.tjcm.tjcminspectmanager.model.HiddenTroubleItem;
import com.tjcm.tjcminspectmanager.model.KeyValue;
import com.tjcm.tjcminspectmanager.model.PlanItem;
import com.tjcm.tjcminspectmanager.model.TaskItem;
import com.tjcm.tjcminspectmanager.model.User;

public final class NetManager
{

    public static final String CODE_IO    = "IOEXCEPTION";
    public static final String CODE_PARSE = "PARSEEXCEPTION";
    public static String       URL_LOGIN  = null;
    public static String       URL_DATA   = null;

    private static final int   timeout    = 12000;

    private NetManager()
    {
    }

    public static User login(String name, String password) throws CodeException
    {
        HttpResponseResultStream stream = null;
        try
        {
            stream = HttpConnectionManager.doGetForStream(URL_LOGIN + "?username=" + URLEncoder.encode(name, "utf-8") + "&password=" + URLEncoder.encode(password, "utf-8"), true, timeout, null);
            InputStream input = stream.getResultStream();
            DataInputStream inputPack = new DataInputStream(input);
            int code = inputPack.readInt();
            if (code != 100)
                throw new CodeException(code + "");
            short length = inputPack.readShort();
            byte[] data = new byte[length];
            inputPack.readFully(data);
            stream.close();
            String response = decodeUnicode(new String(data, "ASCII"));
            String[] info = response.split(",,");
            User user = new User();
            user.userName = name;
            user.userId = info[0];
            user.areaName = info[1];
            user.specialtyType = info[2];
            return user;
        } catch (IOException e)
        {
            throw new CodeException(CODE_IO, e);
        } finally
        {
            try
            {
                if (stream != null)
                    stream.close();
            } catch (IOException e)
            {
                throw new CodeException(CODE_IO, e);
            }
        }
    }

    private static String decodeUnicode(String s)
    {
        StringBuilder sb = new StringBuilder(s.length());
        char[] chars = s.toCharArray();
        for (int i = 0; i < chars.length; i++)
        {
            char c = chars[i];
            if (c == '\\' && chars[i + 1] == 'u')
            {
                char cc = 0;
                for (int j = 0; j < 4; j++)
                {
                    char ch = Character.toLowerCase(chars[i + 2 + j]);
                    if ('0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f')
                    {
                        cc |= (Character.digit(ch, 16) << (3 - j) * 4);
                    } else
                    {
                        cc = 0;
                        break;
                    }
                }
                if (cc > 0)
                {
                    i += 5;
                    sb.append(cc);
                    continue;
                }
            }
            sb.append(c);
        }
        return sb.toString();
    }

    private static String doXmlPost(String xml, byte sign) throws CodeException
    {
        HttpResponseResultStream stream = null;
        try
        {
            byte[] xmlByte = xml.getBytes("utf-8");
            int xmlLength = xmlByte.length;
            byte[] postData = new byte[xmlLength + 3];
            postData[0] = sign;
            postData[1] = (byte) (xmlLength >> 8);
            postData[2] = (byte) xmlLength;
            for (int i = 3; i < postData.length; i++)
            {
                postData[i] = xmlByte[i - 3];
            }
            stream = HttpConnectionManager.doPostForStream(URL_DATA, true, timeout, null, postData);
            InputStream input = stream.getResultStream();
            DataInputStream inputPack = new DataInputStream(input);
            int code = inputPack.readInt();
            if (code == 2 || code == 3)
                throw new CodeException(code + "");
            short length = inputPack.readShort();
            byte[] data = new byte[length];
            inputPack.readFully(data);
            stream.close();
            return decodeUnicode(new String(data, "ASCII"));
        } catch (IOException e)
        {
            throw new CodeException(CODE_IO, e);
        } finally
        {
            try
            {
                if (stream != null)
                    stream.close();
            } catch (IOException e)
            {
                throw new CodeException(CODE_IO, e);
            }
        }
    }

    private static ContentItem[] doXmlPostAndParse(String xml, byte sign) throws CodeException
    {
        String response = doXmlPost(xml, sign);
        if ("^^null,,||,,$$".equals(response))
            return new ContentItem[0];
        String[] responseArr = response.split("\\$\\$");
        ContentItem[] returnVal = new ContentItem[responseArr.length];
        for (int i = 0; i < responseArr.length; i++)
        {
            if (responseArr[i].startsWith("^^"))
                responseArr[i] = responseArr[i].substring(2);
            int index = responseArr[i].indexOf("||");
            if (index == -1)
                throw new CodeException(CODE_PARSE);
            String commonValuesText = responseArr[i].substring(0, index);
            String keyValuesText = responseArr[i].substring(index + 2);
            String[] commonValues = null;
            if (commonValuesText.equals(""))
                commonValues = new String[0];
            else
                commonValues = commonValuesText.split(",,");
            KeyValue[] keyValues = null;
            if (keyValuesText.equals(""))
                keyValues = new KeyValue[0];
            else
            {
                String[] keys = keyValuesText.split(";;");
                keyValues = new KeyValue[keys.length];
                for (int j = 0; j < keys.length; j++)
                {
                    String[] keyArr = keys[j].split("::");
                    if (keyArr.length != 2)
                        throw new CodeException(CODE_PARSE);
                    keyValues[j] = new KeyValue();
                    keyValues[j].name = keyArr[0];
                    keyValues[j].value = keyArr[1];
                }
            }
            returnVal[i] = new ContentItem(commonValues, keyValues);
        }
        return returnVal;
    }

    private static void doXmlPostNoResult(String xml, byte sign) throws CodeException
    {
        HttpResponseResultStream stream = null;
        try
        {
            byte[] xmlByte = xml.getBytes("utf-8");
            int xmlLength = xmlByte.length;
            byte[] postData = new byte[xmlLength + 3];
            postData[0] = sign;
            postData[1] = (byte) (xmlLength >> 8);
            postData[2] = (byte) xmlLength;
            for (int i = 3; i < postData.length; i++)
            {
                postData[i] = xmlByte[i - 3];
            }
            stream = HttpConnectionManager.doPostForStream(URL_DATA, true, timeout, null, postData);
            InputStream input = stream.getResultStream();
            DataInputStream inputPack = new DataInputStream(input);
            int code = inputPack.readInt();
            if (code == 2 || code == 3)
                throw new CodeException(code + "");
        } catch (IOException e)
        {
            throw new CodeException(CODE_IO, e);
        } finally
        {
            try
            {
                if (stream != null)
                    stream.close();
            } catch (IOException e)
            {
                throw new CodeException(CODE_IO, e);
            }
        }
    }

    public static void pointCollectSubmit(String time, String spName, String specialtyType, String lon, String lat, String userId, String area, String level) throws CodeException
    {
        StringBuilder strBuilder = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        strBuilder.append("<data>");
        strBuilder.append("<time>" + time + "</time>");
        strBuilder.append("<spname>" + spName + "</spname>");
        strBuilder.append("<spec_type>" + specialtyType + "</spec_type>");
        strBuilder.append("<longitude>" + lon + "</longitude>");
        strBuilder.append("<latitude>" + lat + "</latitude>");
        strBuilder.append("<dw_user>" + userId + "</dw_user>");
        strBuilder.append("<area>" + area + "</area>");
        strBuilder.append("<trob_grade>" + level + "</trob_grade>");
        strBuilder.append("</data>");
        doXmlPostNoResult(strBuilder.toString(), (byte) 5);
    }

    public static TaskItem[] queryTaskItems(String userId, boolean isPending, int pageIndex) throws CodeException
    {
        StringBuilder strBuilder = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        strBuilder.append("<data>");
        strBuilder.append("<dw_user_id>" + userId + "</dw_user_id>");
        int type;
        if (isPending)
            type = 0;
        else
            type = 1;
        strBuilder.append("<typeIndex>" + type + "</typeIndex>");
        strBuilder.append("<intPage>" + pageIndex + "</intPage>");
        strBuilder.append("</data>");
        ContentItem[] items = doXmlPostAndParse(strBuilder.toString(), (byte) 18);
        TaskItem[] taskItems = new TaskItem[items.length];
        for (int i = 0; i < items.length; i++)
        {
            String[] taskArr = items[i].getCommonValues();
            if (taskArr.length < 8)
                throw new CodeException(CODE_PARSE);
            taskItems[i] = new TaskItem();
            taskItems[i].taskId = taskArr[0];
            taskItems[i].taskType = taskArr[1];
            taskItems[i].taskName = taskArr[2];
            taskItems[i].spotName = taskArr[3];
            taskItems[i].startTime = taskArr[4];
            taskItems[i].endTime = taskArr[5];
            taskItems[i].taskWay = taskArr[6];
            taskItems[i].pageCount = taskArr[7];
            taskItems[i].keyValues = items[i].getKeyValues();
        }
        return taskItems;
    }

    public static void startPendingTask(String userId, String taskId) throws CodeException
    {
        StringBuilder strBuilder = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        strBuilder.append("<data>");
        strBuilder.append("<task_id>" + taskId + "</task_id>");
        strBuilder.append("<dw_user_id>" + userId + "</dw_user_id>");
        strBuilder.append("<flag>start</flag>");
        strBuilder.append("</data>");
        doXmlPostNoResult(strBuilder.toString(), (byte) 19);
    }

    public static ContentItem[] loadTaskTemplate(String taskType) throws CodeException
    {
        StringBuilder strBuilder = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        strBuilder.append("<data>");
        strBuilder.append("<task_type>" + taskType + "</task_type>");
        strBuilder.append("</data>");
        return doXmlPostAndParse(strBuilder.toString(), (byte) 20);
    }

    public static void submitTaskTemplate(String xmlText) throws CodeException
    {
        doXmlPostNoResult(xmlText, (byte) 21);
    }

    public static PlanItem[] queryPlanItems(String userId, int pageIndex) throws CodeException
    {
        StringBuilder strBuilder = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        strBuilder.append("<data>");
        strBuilder.append("<dw_user_id>" + userId + "</dw_user_id>");
        strBuilder.append("<intPage>" + pageIndex + "</intPage>");
        strBuilder.append("</data>");
        ContentItem[] items = doXmlPostAndParse(strBuilder.toString(), (byte) 15);
        PlanItem[] planItems = new PlanItem[items.length];
        for (int i = 0; i < items.length; i++)
        {
            String[] planArr = items[i].getCommonValues();
            if (planArr.length < 10)
                throw new CodeException(CODE_PARSE);
            planItems[i] = new PlanItem();
            planItems[i].planId = planArr[0];
            planItems[i].modelId = planArr[1];
            planItems[i].planName = planArr[2];
            planItems[i].startTime = planArr[3];
            planItems[i].endTime = planArr[4];
            planItems[i].processTimes = planArr[5];
            planItems[i].inspectWay = planArr[6];
            planItems[i].reportGap = planArr[7];
            planItems[i].pageCount = planArr[8];
            planItems[i].sbName = planArr[9];
        }
        return planItems;
    }

    public static void troubleReport(String time, String userId, String area, String important, String lon, String lat, String type, String troubleType, String desc, String level)
            throws CodeException
    {
        StringBuilder strBuilder = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        strBuilder.append("<data>");
        strBuilder.append("<time>" + time + "</time>");
        strBuilder.append("<dw_user>" + userId + "</dw_user>");
        strBuilder.append("<area>" + area + "</area>");
        strBuilder.append("<isImportant>" + important + "</isImportant>");
        strBuilder.append("<longitude>" + lon + "</longitude>");
        strBuilder.append("<latitude>" + lat + "</latitude>");
        strBuilder.append("<spec_type>" + type + "</spec_type>");
        strBuilder.append("<trob_spec_type>" + troubleType + "</trob_spec_type>");
        strBuilder.append("<memo>" + desc + "</memo>");
        strBuilder.append("<trob_grade>" + level + "</trob_grade>");
        strBuilder.append("</data>");
        doXmlPostNoResult(strBuilder.toString(), (byte) 6);
    }

    public static HiddenTroubleItem[] queryTroubleItems(String type, String area, String lon, String lat, String level) throws CodeException
    {
        StringBuilder strBuilder = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        strBuilder.append("<data>");
        strBuilder.append("<spec_type>" + type + "</spec_type>");
        strBuilder.append("<area>" + area + "</area>");
        strBuilder.append("<longitude>" + lon + "</longitude>");
        strBuilder.append("<latitude>" + lat + "</latitude>");
        strBuilder.append("<trob_grade>" + level + "</trob_grade>");
        strBuilder.append("</data>");
        ContentItem[] items = doXmlPostAndParse(strBuilder.toString(), (byte) 7);
        HiddenTroubleItem[] troubleItems = new HiddenTroubleItem[items.length];
        for (int i = 0; i < items.length; i++)
        {
            String[] troubleArr = items[i].getCommonValues();
            if (troubleArr.length < 6)
                throw new CodeException(CODE_PARSE);
            troubleItems[i] = new HiddenTroubleItem();
            troubleItems[i].patrolSpotId = troubleArr[0];
            troubleItems[i].specialtyType = troubleArr[1];
            troubleItems[i].troubleType = troubleArr[2];
            troubleItems[i].troubleStatus = troubleArr[3];
            troubleItems[i].timeStamp = troubleArr[4];
            troubleItems[i].memo = troubleArr[5];
        }
        return troubleItems;
    }

    public static void sendGPSData(byte[] gpsData, byte sign, String fileName) throws CodeException
    {
        HttpResponseResultStream stream = null;
        try
        {
            int gpsLength = gpsData.length;
            byte[] postData = new byte[gpsLength + 3];
            postData[0] = sign;
            postData[1] = (byte) (gpsLength >> 8);
            postData[2] = (byte) gpsLength;
            for (int i = 3; i < postData.length; i++)
            {
                postData[i] = gpsData[i - 3];
            }
            Map<String, List<String>> headers = new HashMap<String, List<String>>();
            List<String> header = new ArrayList<String>();
            header.add(postData.length + "");
            headers.put(HttpConnectionManager.HEADER_REQUEST_CONTENT_LENGTH, header);
            header = new ArrayList<String>();
            header.add(fileName);
            headers.put("gps-filename", header);
            stream = HttpConnectionManager.doPostForStream(URL_DATA, true, timeout, headers, postData);
            InputStream input = stream.getResultStream();
            DataInputStream inputPack = new DataInputStream(input);
            int code = inputPack.readInt();
            if (code == 2 || code == 3)
                throw new CodeException(code + "");
        } catch (IOException e)
        {
            throw new CodeException(CODE_IO, e);
        } finally
        {
            try
            {
                if (stream != null)
                    stream.close();
            } catch (IOException e)
            {
                throw new CodeException(CODE_IO, e);
            }
        }
    }

    public static String[] checkUpdate(String curVersion) throws CodeException
    {
        StringBuilder strBuilder = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        strBuilder.append("<data>");
        strBuilder.append("<VERSION>" + curVersion + "</VERSION>");
        strBuilder.append("<CATEGORY>ANDROID_VM</CATEGORY>");
        strBuilder.append("</data>");
        String result = doXmlPost(strBuilder.toString(), (byte) 27);
        try
        {
            Map<String, List<Element>> resultMap = SimpleDomManager.parseData(result, false);
            Map<String, List<Element>> children = resultMap.get("RESPONSE").get(0).getChildren();
            String action = children.get("ACTION").get(0).getText();
            if ("1".equals(action))
                return new String[] { children.get("VERSION").get(0).getText(), children.get("UPDURL").get(0).getText() };
            return null;
        } catch (Exception e)
        {
            throw new CodeException(CODE_PARSE, e);
        }
    }

}
